package wangjg.xuexiban.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

import wangjg.commons.character.DigestUtil;
import android.util.Log;

public class WebLoader {
	private String cacheDir;
//	private int expired = 1000*60;
	private ExecutorService threadPoll = Executors.newFixedThreadPool(1);

	private static WebLoader wl;
	
	public static final WebLoader instance(){
		if(wl==null){
			wl = new WebLoader(Constant.WEB_CACHE_DIR);
		}
		return wl;
	}
	
	private WebLoader(String cacheDir) {
		this.cacheDir = cacheDir;
		File file = new File(this.cacheDir);
		file.mkdirs();
	}
	
	public static void main(String argsp[]){
		WebLoader c = new WebLoader("d:\\temp");
		c.loadData("http://www.qq.com/", null);
	}
	
	public static interface Callback{
		public static final String STATUS_SUCCESS = "NET-SUCCESS";
		public static final String STATUS_FAILURE = "NET-FAILURE";
		public static final String STATUS_LOCAL = "LOCAL";
		
		public void handle(String status, String filePath);
	}
	
	public void loadData(final String url, final Callback callback) {
		new Thread(){
			public void run(){
				_load(url, callback, false);
			}
		}.start();
	}
	
	//本地缓存优先
	public void loadFile(final String url, final Callback callback) {
		threadPoll.submit(new Runnable() {
			public void run() {
				_load(url, callback, true);
			}
		});
	}

	private void _load(final String url, final Callback callback, boolean localFirst) {
		Log.d("_load", "url="+url+",localFirst="+localFirst);
		final String fileName = getCacheFileName(url);
		final String filePath = cacheDir +File.separatorChar+ fileName;
		File file = new File(filePath);
		if(file.exists()){
			if (callback != null) {
				callback.handle(Callback.STATUS_LOCAL, filePath);
			}
			if(localFirst){
				return;
			}
		}else if(callback instanceof FileDownCallback){
			Log.d("not exists", ""+filePath+",url="+url);
		}
		boolean success = download(url, filePath);
		if (callback != null) {
			callback.handle(success?Callback.STATUS_SUCCESS:Callback.STATUS_FAILURE, filePath);
		}
	}
	
	// TODO synchronized 太粗暴 
	public synchronized boolean download(String url, String savePath) {
		HttpClient client = this.getHttpsClient();
		try {
			// 创建 HttpGet 方法，该方法会自动处理 URL 地址的重定向
			HttpGet httpGet = new HttpGet(url);
			HttpResponse response = client.execute(httpGet);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				HttpEntity entity = response.getEntity();
				File file = new File(savePath);
				file.getParentFile().mkdirs();
				OutputStream out = new FileOutputStream(file);
				InputStream in = entity.getContent();
				this.copyAndClose(in, out);
				return true;
			}
		} catch (Exception e) {
			Log.e(this.getClass().getSimpleName(), "保存下载的文件错误", e);
		}finally{
			if(client!=null){
			}
		}
		return false;
	}
	
	protected HttpClient getHttpClient(){
		HttpClient client = new DefaultHttpClient();
		return client;
	}
	
	private String getCacheFileName(String url){
		try {
//			String path = java.net.URLEncoder.encode(url, "utf-8");
//			return path;
			return DigestUtil.SHA256(url);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	String getFileName(HttpResponse response, HttpRequestBase request){
		Header head = response.getFirstHeader("Content-Disposition");
		if(head!=null){
			String str = head.getValue();
			int pos = str.indexOf("filename=");
			return str.substring(pos+9);
		}else{
			String path = request.getURI().getPath();
			int pos = path.lastIndexOf('/');
			return pos==-1?path:path.substring(pos+1);
		}
	}
	
	void copyAndClose(InputStream is, OutputStream os){
		try {
			this.copy(is,os);
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 在流之间拷贝数据
	 * @param is 输入流
	 * @param os 输出流
	 * @throws IOException 读写异常
	 */
	void copy(InputStream is, OutputStream os) throws IOException{
		byte[] buf = new byte[512];
		int count = is.read(buf); 
		while(count!=-1){ 
			os.write(buf,0,count); 
			count = is.read(buf);
		}
	}
	
	protected HttpClient getHttpsClient() {
        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);
            SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore);
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);//允许所有主机的验证

            HttpParams params = new BasicHttpParams();

            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
            HttpProtocolParams.setUseExpectContinue(params, true);

            // 设置连接管理器的超时
            ConnManagerParams.setTimeout(params, 10000);
            // 设置连接超时
            HttpConnectionParams.setConnectionTimeout(params, 10000);
            // 设置socket超时
            HttpConnectionParams.setSoTimeout(params, 10000);

            // 设置http https支持
            SchemeRegistry schReg = new SchemeRegistry();
            schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            schReg.register(new Scheme("https", sf, 443));

            ClientConnectionManager conManager = new ThreadSafeClientConnManager(params, schReg);

            HttpClient httpClient = new DefaultHttpClient(conManager, params);
            return httpClient;
        } catch (Exception e) {
            e.printStackTrace();
            return new DefaultHttpClient();
        }
    }

}

class SSLSocketFactoryEx extends SSLSocketFactory {

	SSLContext sslContext = SSLContext.getInstance("TLS");

	public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
		super(truststore);

		TrustManager tm = new X509TrustManager() {
			@Override
			public java.security.cert.X509Certificate[] getAcceptedIssuers() {
				return null;
			}
			@Override
			public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType)throws java.security.cert.CertificateException {
			}
			@Override
			public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType)throws java.security.cert.CertificateException {
			}
		};
		sslContext.init(null, new TrustManager[] { tm }, null);
	}

	@Override
	public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
		return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
	}

	@Override
	public Socket createSocket() throws IOException {
		return sslContext.getSocketFactory().createSocket();
	}
}
